package com.prodog.command.handler;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ReflectUtil;
import com.prodog.command.annonations.Interceptors;
import com.prodog.command.annonations.Iptor;
import com.prodog.command.entity.GameCommand;
import com.prodog.command.entity.InterceptorsHandleParam;
import com.prodog.command.entity.RoleGameCommand;
import com.prodog.command.interceptor.Interceptor;
import com.prodog.command.interceptor.InterceptorRes;
import com.prodog.utils.bean.SpringBeanUtils;
import com.prodog.utils.dataType.ConvertUtil;
import com.prodog.utils.string.JSONUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.AnnotationUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.*;

public class InterceptorAnnontationHandler {
    public InterceptorRes handle(InterceptorsHandleParam info) {
        InterceptorRes res = InterceptorRes.pass();
        List<Iptor> iptors = new ArrayList<>();
        //类拦截器
        Optional.ofNullable(AnnotationUtils.findAnnotation(info.getObj().getClass(), Interceptors.class)).ifPresent(ins ->
                iptors.addAll(Arrays.asList(ins.iptors()))
        );
        //方法拦截器
        Optional.ofNullable(AnnotationUtils.findAnnotation(info.getMethod(), Interceptors.class)).ifPresent(ins ->
                iptors.addAll(Arrays.asList(ins.iptors()))
        );
        if (CollectionUtil.isNotEmpty(iptors)) {
            Map<String, Object> params = buildInterceptorParams(info.getMethod().getParameters(), info.getArgs());
            for (Iptor iptor : iptors) {
                Map<String, Object> interceptorParams = new HashMap<>();
                interceptorParams.putAll(params);
                String paramsStr = iptor.params().replace("'", "\"");
                if (paramsStr != null && !paramsStr.trim().equals("")) {
                    try {
                        interceptorParams.putAll(JSONUtils.parseObj(paramsStr, Map.class));
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                Interceptor interceptor = SpringBeanUtils.getBean(iptor.value());
                GameCommand command = (GameCommand) interceptorParams.values().stream().filter(param -> param instanceof GameCommand).findAny().get();
                res = interceptor.intercept(command, interceptorParams, iptor.msg());
                if (!res.isPass()) {
                    return res;
                }
            }
        }
        return res;
    }

    private Map<String, Object> buildInterceptorParams(Parameter[] parameters, Object[] args) {
        Map<String, Object> params = new HashMap<>();
        for (int i = 0; i < parameters.length; i++) {
            Parameter parameter = parameters[i];
            Object arg = args[i];
            if (parameter.getType().equals(GameCommand.class) || parameter.getType().equals(RoleGameCommand.class)) {
                params.put(parameter.getName(), arg);
                continue;
            } else if (ConvertUtil.isSimpleType(parameter.getType())) {
                //基本类型注入
                params.put(parameter.getName(), arg);
            } else {
                Map<String, Field> fieldMap = ReflectUtil.getFieldMap(parameter.getType());
                fieldMap.forEach((name, field) -> params.put(name, ReflectUtil.getFieldValue(arg, field)));
            }
        }
        return params;
    }

    public static InterceptorRes handleInterceptors(JoinPoint point) {
        try {
            MethodSignature target = (MethodSignature) point.getSignature();
            Method method = target.getMethod();
            InterceptorsHandleParam proxyInvokeInfo = new InterceptorsHandleParam(point.getTarget(), method, point.getArgs());
            return new InterceptorAnnontationHandler().handle(proxyInvokeInfo);
        } catch (Exception e) {
            e.printStackTrace();
            return InterceptorRes.intercept("服务器发生错误。");
        }
    }
}
